package com.ruoyi.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.common.EsIndex;
import com.ruoyi.system.domain.PageInfoCustom;
import com.ruoyi.system.domain.PoPublicOpinion;
import com.ruoyi.system.domain.PublicOpinionEvents;
import com.ruoyi.system.domain.PublicOpinionTopic;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.enums.ChinaMediaTypeEnum;
import com.ruoyi.system.service.ElasticsearchQueryBuilderService;
import com.ruoyi.system.service.IPublicOpinionEventsService;
import com.ruoyi.system.service.IPublicOpinionTopicService;
import com.ruoyi.system.util.KeyWordUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.*;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.text.DecimalFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgs
 * @Description: 索引文档，即往索引里面放入文档数据.类似于数据库里面向表里面插入一行数据，一行数据就是一个文档
 * @date 2018年6月23日
 */
@Service
public class EsUtil {
    private static Logger logger = LogManager.getRootLogger();
    @Autowired
    private IPublicOpinionTopicService poEventOpinionRelationService;

    @Autowired
    private IPublicOpinionEventsService publicOpinionEventsService;

    @Autowired
    private IPublicOpinionTopicService publicOpinionTopicService;

    @Autowired
    private ElasticsearchQueryBuilderService elasticsearchQueryBuilderService;

    @Resource(name = "restHighLevelClient")
    RestHighLevelClient restHighLevelClient;

    private static RestHighLevelClient client;

    /**
     * @PostContruct是spring框架的注解 spring容器初始化的时候执行该方法
     */
    @PostConstruct
    public void init() {
        client = this.restHighLevelClient;
    }


    /**
     * 此方法修改索引慎用，需要获取到索引的全部字段信息进行修改，字段类型难以对应。
     *
     * @param opinion
     */
    public void indexOpinion(PoPublicOpinion opinion) {
        try {
            // 1、创建索引请求
            IndexRequest request = new IndexRequest(
                    EsIndex.OPINION);   //索引

            if (StringUtils.isEmpty(opinion.getId())) {
                opinion.setId(UUID.randomUUID().toString());
            }
            request.id(opinion.getId());
            // 2、准备文档数据
            // 方式一：直接给JSON串
            System.out.println(JSONObject.toJSONString(opinion));

            request.source(JSONObject.toJSONString(opinion), XContentType.JSON);

            //4、发送请求
            IndexResponse indexResponse = null;
            try {
                // 同步方式
                indexResponse = client.index(request, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (indexResponse != null) {
                String index = indexResponse.getIndex();
                String type = indexResponse.getType();
                String id = indexResponse.getId();
                long version = indexResponse.getVersion();
                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    System.out.println("新增文档成功，处理逻辑代码写到这里。");
                } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                    System.out.println("修改文档成功，处理逻辑代码写到这里。");
                }
                // 分片处理信息
                ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                if (shardInfo.getTotal() != shardInfo.getSuccessful()) {

                }
                // 如果有分片副本失败，可以获得失败原因信息
                if (shardInfo.getFailed() > 0) {
                    for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                        String reason = failure.reason();
                        System.out.println("副本失败原因：" + reason);
                    }
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 返回全部不分页
     * (支持高亮)
     * 根据事件定义查询舆情（支持去重）
     *
     * @param event
     * @param repeatState
     * @return
     */
    public List<PoPublicOpinion> getEventOpinions(PublicOpinionEvents event, Boolean repeatState) {
        EventParameterVo parameter = new EventParameterVo();
        parameter.setRepeatState(repeatState);
        SearchSourceBuilder sourceBuilder = buildSearchSourceBuilder(event, parameter, null);
        List<PoPublicOpinion> opinions = null;
        try {
            opinions = search(sourceBuilder, PoPublicOpinion.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return opinions;
    }


    /**
     * 查询封装，返回全部集合--不分页
     *
     * @param searchSourceBuilder
     * @param s
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> List<T> search(SearchSourceBuilder searchSourceBuilder, Class<T> s) throws Exception {
        final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        searchRequest.source(searchSourceBuilder);
        searchRequest.scroll(scroll);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        String scrollId = searchResponse.getScrollId();
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        long totalHits = searchResponse.getHits().getTotalHits().value;
        logger.info("es查询集合总数为{}", totalHits);

        JSONArray jsonArray = new JSONArray();
        while (searchHits != null && searchHits.length > 0) {
            for (SearchHit hit : searchResponse.getHits().getHits()) {
                String sourceAsString = hit.getSourceAsString();
                JSONObject jsonObject = JSON.parseObject(sourceAsString);
                jsonArray.add(jsonObject);
            }
            SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
            scrollRequest.scroll(scroll);
            searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT);
            scrollId = searchResponse.getScrollId();
            searchHits = searchResponse.getHits().getHits();
        }

        // 清除滚屏
        if (scrollId != null) {
            ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
            clearScrollRequest.addScrollId(scrollId);
            ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
            boolean succeeded = clearScrollResponse.isSucceeded();
        }

        // 封装集合
        List<T> list = jsonArray.toJavaList(s);
        return list;
    }


    public List<PoPublicOpinion> getMatchOpinionByIds(List<String> opinionIds) {
        List<PoPublicOpinion> opinions = new ArrayList<>();
        try {

            // 1、创建search请求
            SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);

            // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            //构造QueryBuilder
            QueryBuilder matchQueryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termsQuery("id", opinionIds));

            sourceBuilder.query(matchQueryBuilder);

            searchRequest.source(sourceBuilder);

            //3、发送请求
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


            //4、处理响应
            if (RestStatus.OK.equals(searchResponse.status())) {
                //处理搜索命中文档结果
                SearchHits hits = searchResponse.getHits();
                TotalHits totalHits = hits.getTotalHits();

                sourceBuilder.query(matchQueryBuilder).from(0).size((int) totalHits.value);
                searchRequest.source(sourceBuilder);

                //3、发送请求
                searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
                hits = searchResponse.getHits();
                SearchHit[] searchHits = hits.getHits();

                for (SearchHit hit : searchHits) {
                    String sourceAsString = hit.getSourceAsString(); //取成json串
                    PoPublicOpinion opinion = JSON.parseObject(sourceAsString, PoPublicOpinion.class);
                    opinions.add(opinion);
                }
            }

        } catch (IOException e) {
            logger.error(e);
        }
        return opinions;

    }


    /**
     * 根据舆情id查询舆情详情
     *
     * @param id
     * @return
     */
    public PoPublicOpinion selectPoPublicOpinionById(String id) {

        try {

            // 1、创建search请求
            SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);

            // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            //构造QueryBuilder
            QueryBuilder matchQueryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("id", id));

            sourceBuilder.query(matchQueryBuilder);

            searchRequest.source(sourceBuilder);

            //3、发送请求
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


            //4、处理响应
            if (RestStatus.OK.equals(searchResponse.status())) {
                //处理搜索命中文档结果
                SearchHits hits = searchResponse.getHits();
                TotalHits totalHits = hits.getTotalHits();

                sourceBuilder.query(matchQueryBuilder).from(0).size((int) totalHits.value);
                searchRequest.source(sourceBuilder);

                //3、发送请求
                searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
                hits = searchResponse.getHits();
                SearchHit[] searchHits = hits.getHits();

                for (SearchHit hit : searchHits) {
                    String sourceAsString = hit.getSourceAsString(); //取成json串
                    PoPublicOpinion opinion = JSON.parseObject(sourceAsString, PoPublicOpinion.class);
                    return opinion;
                }
            }

        } catch (IOException e) {
            logger.error(e);
        }
        return null;
    }

    public BoolQueryBuilder buildBoolQueryBuilder(PoPublicOpinion opinion) {
        //构造QueryBuilder
        BoolQueryBuilder matchQueryBuilder = QueryBuilders.boolQuery();
        if (opinion != null) {
            if (StringUtils.isNotEmpty(opinion.getKeywords())) {
                matchQueryBuilder.must(QueryBuilders.matchQuery("title", opinion.getKeywords()));
            }
            if (StringUtils.isNotEmpty(opinion.getTitle())) {
                matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("title", opinion.getTitle()));
            }
            if (StringUtils.isNotEmpty(opinion.getContent())) {
                matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("content", opinion.getTitle()));
            }
            if (StringUtils.isNotEmpty(opinion.getMediaName())) {
                matchQueryBuilder.must(QueryBuilders.termQuery("siteName", opinion.getMediaName()));
            }
            if (StringUtils.isNotEmpty(opinion.getMediaType())) {
                matchQueryBuilder.must(QueryBuilders.termQuery("mediaType", opinion.getMediaType()));
            }
            if (StringUtils.isNotEmpty(opinion.getAuthor())) {
                matchQueryBuilder.must(QueryBuilders.termQuery("author", opinion.getAuthor()));
            }
        }

        return matchQueryBuilder;
    }


    public HashMap getOpinionsByParameter(EventParameterVo parameter, PoPublicOpinion opinion, Integer pageNum, Integer pageSize) {
        BoolQueryBuilder queryBuilder = buildBoolQueryBuilder(opinion);

        queryBuilder = buildBoolQueryBuilder(queryBuilder, parameter);

        return getHighLightOpinions(queryBuilder, pageNum, pageSize);
    }

    /**
     * 前端过滤
     *
     * @param queryBuilder
     * @param parameter
     * @return
     */
    private BoolQueryBuilder buildBoolQueryBuilder(BoolQueryBuilder queryBuilder, EventParameterVo parameter) {
        //时间段过滤
        if (StringUtils.isNotEmpty(parameter.getTimeType())) {
            if (!parameter.getTimeType().equals("all")) {
                HashMap hashMap = DateUtils.getStartEndTime(parameter.getTimeType(), parameter.getStartDateTime(), parameter.getEndDateTime());
                Date beginPublishDay = (Date) hashMap.get("beginPublishDay");
                Date endPublishDay = (Date) hashMap.get("endPublishDay");
                queryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(queryBuilder, beginPublishDay, endPublishDay);
            }
        } else if (StringUtils.isEmpty(parameter.getTimeType()) && parameter.getStartDateTime() != null) {
            queryBuilder = elasticsearchQueryBuilderService.boolQueryBuilderStartTime(queryBuilder, parameter.getStartDateTime());
        } else if (StringUtils.isEmpty(parameter.getTimeType()) && parameter.getEndDateTime() != null) {
            queryBuilder = elasticsearchQueryBuilderService.boolQueryBuilderEndTime(queryBuilder, parameter.getEndDateTime());
        }
        //情感过滤
        if (parameter.getIspositive() == 1) {
            queryBuilder.must(QueryBuilders.termQuery("ispositive", parameter.getIspositive()));
        }
        if (parameter.getIsneutral() == 1) {
            queryBuilder.must(QueryBuilders.termQuery("isneutral", parameter.getIsneutral()));
        }
        if (parameter.getIsnegative() == 1) {
            queryBuilder.must(QueryBuilders.termQuery("isnegative", parameter.getIsnegative()));
        }
        //关键词搜索
        if (StringUtils.isNotEmpty(parameter.getKeyWords())) {
            if (StringUtils.isNotEmpty(parameter.getSearchArea()) && parameter.getSearchArea().equals("title")) {
                queryBuilder.must(QueryBuilders.matchPhraseQuery("title", parameter.getKeyWords()));
            } else if (StringUtils.isNotEmpty(parameter.getSearchArea()) && parameter.getSearchArea().equals("content")) {
                queryBuilder.must(QueryBuilders.matchPhraseQuery("content", parameter.getKeyWords()));
            } else {
                queryBuilder.must(QueryBuilders.multiMatchQuery(parameter.getKeyWords(), "title", "content").type(MultiMatchQueryBuilder.Type.PHRASE));
            }
        }
        return queryBuilder;
    }


    public PageInfoCustom<PoPublicOpinion> getMatchOpinionByEventId(PublicOpinionEvents event, Integer pageNum, Integer pageSize, EventParameterVo parameterVo, List<String> bindIds, Boolean repeatState) {
        SearchSourceBuilder sourceBuilder = null;
        if (repeatState != null && repeatState) {
            sourceBuilder = buildCollapseSearchSourceBuilder(event, parameterVo, bindIds);
        } else {
            sourceBuilder = buildSearchSourceBuilder(event, parameterVo, bindIds);
        }
        PageInfoCustom<PoPublicOpinion> opinionPageInfo = null;
        try {
            opinionPageInfo = searchCollapse(sourceBuilder, pageNum, pageSize, PoPublicOpinion.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return opinionPageInfo;
    }


    /**
     * 查询封装，带分页(总数去重)
     *
     * @param searchSourceBuilder
     * @param pageNum
     * @param pageSize
     * @param s
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> PageInfoCustom<T> searchCollapse(SearchSourceBuilder searchSourceBuilder, Integer pageNum, Integer pageSize, Class<T> s) throws Exception {

        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        //分页
        if (pageNum != null && pageSize != null) {
            searchSourceBuilder.from((pageNum - 1) * pageSize);
            searchSourceBuilder.size(pageSize);
        }
        // 设置 track_total_hits 参数（显示具体总数而不是10000）
        searchSourceBuilder.trackTotalHits(true);

        // 聚合统计
        TermsAggregationBuilder aggregation = AggregationBuilders.terms("carrie").field("carrie").size(20);
        searchSourceBuilder.aggregation(aggregation);


        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        JSONArray jsonArray = new JSONArray();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            JSONObject jsonObject = JSON.parseObject(sourceAsString);
            //取高亮结果
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields.get("title") != null) {
                jsonObject.put("title", highlightFields.get("title").fragments()[0].string());
            }
            if (highlightFields.get("content") != null) {
                jsonObject.put("content", highlightFields.get("content").fragments()[0].string());
            }
            jsonArray.add(jsonObject);
        }
        logger.info("返回总数为：" + hits.getTotalHits());
        int total = (int) hits.getTotalHits().value;

        //去重
        if (searchResponse.getAggregations() != null) {
            Aggregations aggregations = searchResponse.getAggregations();
            Cardinality cardinality = aggregations.get("DISTINCT_TOTAL_COUNT");
            if (cardinality != null) {
                logger.info("去重后总数为：" + cardinality.getValue());
                total = (int) cardinality.getValue();
            }
        }
        // 封装分页
        List<T> list = jsonArray.toJavaList(s);
        PageInfoCustom<T> page = new PageInfoCustom<>();
        page.setList(list);
        page.setPageNum(pageNum);
        page.setPageSize(pageSize);
        page.setTotal(total);
        page.setPages(total == 0 ? 0 : (total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1));
        page.setHasNextPage(page.getPageNum() < page.getPages());
        if (searchResponse.getAggregations() != null) {
            List<NameValue> carries = new ArrayList<>();
            Aggregations aggregations = searchResponse.getAggregations();
            Aggregation carrieAggregation = aggregations.get("carrie");

            Terms terms = (Terms) carrieAggregation;
            for (Terms.Bucket bucket : terms.getBuckets()) {
                long value = bucket.getDocCount();
                NameValue nameValue = new NameValue();
                nameValue.setName(bucket.getKey().toString());
                nameValue.setValue((int) value);
                carries.add(nameValue);
            }

            page.setCustom(carries);

        }
        return page;
    }


    /**
     * 支持去重
     *
     * @param event
     * @param parameter
     * @param bindIds
     * @return
     */
    public SearchSourceBuilder buildCollapseSearchSourceBuilder(PublicOpinionEvents event, EventParameterVo parameter, List<String> bindIds) {
        SearchSourceBuilder searchSourceBuilder = buildSearchSourceBuilder(event, parameter, bindIds);
        // 去重功能，此时我们的搜索字段的名称为 headline ，此处需要使用 title.keyword 来进行查询
        CollapseBuilder collapseBuilder = new CollapseBuilder("url");
        searchSourceBuilder.collapse(collapseBuilder);
        AggregationBuilder aggregation = AggregationBuilders.cardinality("DISTINCT_TOTAL_COUNT").field("url");
        searchSourceBuilder.aggregation(aggregation);
        return searchSourceBuilder;
    }


    public HashMap getHighLightOpinions(BoolQueryBuilder queryBuilder, Integer pageNum, Integer pageSize) {
        List<PoPublicOpinion> poPublicOpinions = new ArrayList<>();
        HashMap resultHm = new HashMap();
        try {

            // 1、创建search请求
            SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);

            // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(queryBuilder);
            sourceBuilder.from((pageNum - 1) * pageSize);
            sourceBuilder.size(pageSize);
//            sourceBuilder.sort("id", SortOrder.DESC);

            // 高亮设置
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.requireFieldMatch(false).field("title")
                    .preTags("<strong><font color=\"#FF0000\">").postTags("</font></strong>");


            sourceBuilder.highlighter(highlightBuilder);

            searchRequest.source(sourceBuilder);

            //3、发送请求
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


            //4、处理响应
            if (RestStatus.OK.equals(searchResponse.status())) {
                //处理搜索命中文档结果
                SearchHits hits = searchResponse.getHits();
                TotalHits totalHits = hits.getTotalHits();
                resultHm.put("total", totalHits.value);


                SearchHit[] searchHits = hits.getHits();
                for (SearchHit hit : searchHits) {
                    String index = hit.getIndex();
                    String type = hit.getType();
                    String id = hit.getId();
                    float score = hit.getScore();

                    String sourceAsString = hit.getSourceAsString(); //取成json串
                    PoPublicOpinion opinion = JSON.parseObject(sourceAsString, PoPublicOpinion.class);

                    //取_source字段值
                    //String sourceAsString = hit.getSourceAsString(); //取成json串
                    Map<String, Object> sourceAsMap = hit.getSourceAsMap(); // 取成map对象
                    //从map中取字段值
                /*String title = (String) sourceAsMap.get("title");
                String content  = (String) sourceAsMap.get("content"); */
                    System.out.println("index:" + index + "  type:" + type + "  id:" + id);
                    System.out.println("sourceMap : " + sourceAsMap);
                    //取高亮结果
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    HighlightField highlight = highlightFields.get("title");
                    if (highlight != null) {
                        Text[] fragments = highlight.fragments();  //多值的字段会有多个值
                        if (fragments != null) {
                            String fragmentString = fragments[0].string();
                            System.out.println("title highlight : " + fragmentString);
                            //可用高亮字符串替换上面sourceAsMap中的对应字段返回到上一级调用
                            //sourceAsMap.put("title", fragmentString);
                            opinion.setTitle(fragments[0].string());
                        }
                    }
                    poPublicOpinions.add(opinion);
                }
            }

        } catch (IOException e) {
            logger.error(e);
        }
        resultHm.put("list", poPublicOpinions);
        return resultHm;
    }


    /**
     * 查询封装，返回ID集合(10000条)
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<String> search10000(SearchSourceBuilder searchSourceBuilder) throws Exception {

        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        searchSourceBuilder.fetchSource("id", "");
        searchSourceBuilder.size(10000);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        SearchHit[] searchHits = searchResponse.getHits().getHits();
        long totalHits = searchResponse.getHits().getTotalHits().value;
        logger.info("es查询集合总数为{}", totalHits);

        // 封装集合
        List<String> list = new ArrayList<>();

        for (SearchHit hit : searchHits) {
            if (hit.getSourceAsMap().get("id") != null) {
                String id = hit.getSourceAsMap().get("id").toString();
                list.add(id);
            }
        }


        return list;
    }


    private int getCount(RestHighLevelClient client, SearchRequest searchRequest, SearchSourceBuilder sourceBuilder, BoolQueryBuilder matchQueryBuilder) {
        sourceBuilder.query(matchQueryBuilder);

        searchRequest.source(sourceBuilder);

        //3、发送请求
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            //4、处理响应
            if (RestStatus.OK.equals(searchResponse.status())) {
                //处理搜索命中文档结果
                SearchHits hits = searchResponse.getHits();
                TotalHits totalHits = hits.getTotalHits();
                return (int) totalHits.value;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;

    }

    public void indexEvent(PublicOpinionEvents event) {
        try {
            // 1、创建索引请求
            IndexRequest request = new IndexRequest(
                    EsIndex.EVENT);   //索引
            request.id(event.getEventId().toString());
            // 2、准备文档数据
            // 方式一：直接给JSON串
            System.out.println(JSONObject.toJSONString(event));

            request.source(JSONObject.toJSONString(event), XContentType.JSON);

            // 方式二：以map对象来表示文档
            /*
            Map<String, Object> jsonMap = new HashMap<>();
            jsonMap.put("user", "kimchy");
            jsonMap.put("postDate", new Date());
            jsonMap.put("message", "trying out Elasticsearch");
            request.source(jsonMap);
            */

            // 方式三：用XContentBuilder来构建文档
            /*
            XContentBuilder builder = XContentFactory.jsonBuilder();
            builder.startObject();
            {
                builder.field("user", "kimchy");
                builder.field("postDate", new Date());
                builder.field("message", "trying out Elasticsearch");
            }
            builder.endObject();
            request.source(builder);
            */

            // 方式四：直接用key-value对给出
            /*
            request.source("user", "kimchy",
                            "postDate", new Date(),
                            "message", "trying out Elasticsearch");
            */

            //3、其他的一些可选设置
            /*
            request.routing("routing");  //设置routing值
            request.timeout(TimeValue.timeValueSeconds(1));  //设置主分片等待时长
            request.setRefreshPolicy("wait_for");  //设置重刷新策略
            request.version(2);  //设置版本号
            request.opType(DocWriteRequest.OpType.CREATE);  //操作类别
            */

            //4、发送请求
            IndexResponse indexResponse = null;
            try {
                // 同步方式
                indexResponse = client.index(request, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (indexResponse != null) {
                String index = indexResponse.getIndex();
                String type = indexResponse.getType();
                String id = indexResponse.getId();
                long version = indexResponse.getVersion();
                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    System.out.println("新增文档成功，处理逻辑代码写到这里。");
                } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                    System.out.println("修改文档成功，处理逻辑代码写到这里。");
                }
                // 分片处理信息
                ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                if (shardInfo.getTotal() != shardInfo.getSuccessful()) {

                }
                // 如果有分片副本失败，可以获得失败原因信息
                if (shardInfo.getFailed() > 0) {
                    for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                        String reason = failure.reason();
                        System.out.println("副本失败原因：" + reason);
                    }
                }
            }


            //异步方式发送索引请求
            /*ActionListener<IndexResponse> listener = new ActionListener<IndexResponse>() {
                @Override
                public void onResponse(IndexResponse indexResponse) {

                }

                @Override
                public void onFailure(Exception e) {

                }
            };
            client.indexAsync(request, listener);
            */

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public HashMap getTopicOpinions(PublicOpinionTopic topic, TopicParameterVo parameterVo, Integer pageNum, Integer pageSize, Boolean repeatState) {
        HashMap resultHm = new HashMap();
        List<PoPublicOpinion> opinions = new ArrayList<>();
        try {

            // 1、创建search请求
            SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);

            // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            //构造QueryBuilder
            BoolQueryBuilder matchQueryBuilder = QueryBuilders.boolQuery();

//            如果是指定媒体监测
            if (topic.getType().equals("domestic")) {
                matchQueryBuilder.must(QueryBuilders.matchQuery("siteName", topic.getMonitoringMedia()));
            } else if (topic.getType().equals("overseas")) {
                List<String> mediaSites = KeyWordUtils.transformationOr(topic.getMonitoringMedia());
                matchQueryBuilder.must(QueryBuilders.termsQuery("siteName", mediaSites));
            }

            matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, topic.getSearchArea(), topic.getRelatedWords(), topic.getOpinionWords(), topic.getExclusionWords());


            if (repeatState != null && repeatState) {
                // 去重功能，此时我们的搜索字段的名称为 headline ，此处需要使用 headline.keyword 来进行查询
                CollapseBuilder collapseBuilder = new CollapseBuilder("url");
                sourceBuilder.collapse(collapseBuilder);

                // 设置第二个字段的折叠行为
                CollapseBuilder titleCollapseBuilder = new CollapseBuilder("title");
                sourceBuilder.collapse(titleCollapseBuilder);
            }

            //前端提交测关键词和查询区域
            if (StringUtils.isNotEmpty(parameterVo.getKeyWords())) {
                //QueryBuilders.matchQuery是用于执行全文本搜索的查询，它会对查询的文本进行分词，然后进行匹配。例如，如果我们使用matchQuery搜索"quick brown fox"，它将匹配包含"quick"、"brown"和"fox"中任意一个单词的文档。
//                if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("title")) {
//                    matchQueryBuilder.must(QueryBuilders.matchQuery("title", parameterVo.getKeyWords()));
//                } else if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("content")) {
//                    matchQueryBuilder.must(QueryBuilders.matchQuery("content", parameterVo.getKeyWords()));
//                } else {
//                    matchQueryBuilder.must(QueryBuilders.multiMatchQuery(parameterVo.getKeyWords(), "title", "content"));
//                }
                //QueryBuilders.matchPhraseQuery则是用于执行短语匹配的查询，它要求匹配的文本必须包含完整的短语，而不是单个词的匹配。例如，如果我们使用matchPhraseQuery搜索"quick brown fox"，它将只匹配包含"quick brown fox"这个短语的文档，而不会匹配包含"quick"、"brown"和"fox"中任意一个单词的文档。

                if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("title")) {
                    matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("title", parameterVo.getKeyWords()));
                } else if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("content")) {
                    matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("content", parameterVo.getKeyWords()));
                } else {
                    matchQueryBuilder.must(QueryBuilders.multiMatchQuery(parameterVo.getKeyWords(), "title", "content")
                            .type(MultiMatchQueryBuilder.Type.PHRASE));
                }
            }
            //查询的时间段
            if (StringUtils.isNotEmpty(parameterVo.getTimeType()) && !parameterVo.getTimeType().equals("all")) {
                HashMap hashMap = DateUtils.getStartEndTime(parameterVo.getTimeType(), parameterVo.getStartDateTime(), parameterVo.getEndDateTime());
                Date beginPublishDay = (Date) hashMap.get("beginPublishDay");
                Date endPublishDay = (Date) hashMap.get("endPublishDay");
                matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, beginPublishDay, endPublishDay);
            }
            //情感
            if (parameterVo.getIspositive() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("ispositive", parameterVo.getIspositive()));
            }
            if (parameterVo.getIsneutral() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("isneutral", parameterVo.getIsneutral()));
            }
            if (parameterVo.getIsnegative() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("isnegative", parameterVo.getIsnegative()));
            }
            //媒体类型
            if (parameterVo.getMediaType() != null && parameterVo.getMediaType().size() > 0) {
                matchQueryBuilder.must(QueryBuilders.termsQuery("carrie", parameterVo.getMediaType()));
            }
            //媒体名称
            if (parameterVo.getMediaName() != null && parameterVo.getMediaName().size() > 0) {
                matchQueryBuilder.must(QueryBuilders.termsQuery("siteName", parameterVo.getMediaName()));
            }

            sourceBuilder.query(matchQueryBuilder);

            if (pageNum != null && pageSize != null) {
                sourceBuilder.from((pageNum - 1) * pageSize);
                sourceBuilder.size(pageSize);
            }

            // 高亮设置
            HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
            highlightBuilder.field("title");      //高亮查询字段
            highlightBuilder.field("content");      //高亮查询字段
            highlightBuilder.field("opinionWords");      //高亮查询字段
            highlightBuilder.field("relatedWords");      //高亮查询字段
            highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
            highlightBuilder.preTags("<font color=\"#FF0000\">");   //高亮设置
            highlightBuilder.postTags("</font>");
            sourceBuilder.highlighter(highlightBuilder);

            // 设置 track_total_hits 参数（显示具体总数而不是10000）
            sourceBuilder.trackTotalHits(true);

            //排序
            if (parameterVo.getSort() != null && parameterVo.getSort().equals("desc")) {
                List<SortBuilder<?>> sorts = new ArrayList<>();
                SortBuilder sortBuilder = SortBuilders.fieldSort("publishTime").order(SortOrder.DESC);
                sorts.add(sortBuilder);
                sourceBuilder.sort(sorts);
            } else if (parameterVo.getSort() != null && parameterVo.getSort().equals("asc")) {
                List<SortBuilder<?>> sorts = new ArrayList<>();
                SortBuilder sortBuilder = SortBuilders.fieldSort("publishTime").order(SortOrder.ASC);
                sorts.add(sortBuilder);
                sourceBuilder.sort(sorts);
            }

            // 聚合统计
            TermsAggregationBuilder aggregation = AggregationBuilders.terms("carrie").field("carrie").size(20);
            sourceBuilder.aggregation(aggregation);

            searchRequest.source(sourceBuilder);


            //3、发送请求
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


            //4、处理响应
            if (RestStatus.OK.equals(searchResponse.status())) {
                //处理搜索命中文档结果
                SearchHits hits = searchResponse.getHits();
                TotalHits totalHits = hits.getTotalHits();
                resultHm.put("total", totalHits.value);
                SearchHit[] searchHits = hits.getHits();
                for (SearchHit hit : searchHits) {
                    String sourceAsString = hit.getSourceAsString(); //取成json串
                    PoPublicOpinion opinion = JSON.parseObject(sourceAsString, PoPublicOpinion.class);
                    //取高亮结果
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    opinion.setContent(highlightFields.get("content") != null ?
                            highlightFields.get("content").fragments()[0].string() : opinion.getContent());
                    opinion.setTitle(highlightFields.get("title") != null ?
                            highlightFields.get("title").fragments()[0].string() : opinion.getTitle());
                    opinions.add(opinion);
                }
                List<NameValue> list = new ArrayList<>();
                Aggregations aggregations = searchResponse.getAggregations();
                for (Aggregation a : aggregations) {
                    Terms terms = (Terms) a;
                    for (Terms.Bucket bucket : terms.getBuckets()) {
                        long value = bucket.getDocCount();
                        NameValue nameValue = new NameValue();
                        nameValue.setName(bucket.getKey().toString());
                        nameValue.setValue((int) value);
                        list.add(nameValue);
                    }
                }
                resultHm.put("carrie", list);
            }


        } catch (IOException e) {
            logger.error(e);
        }
        resultHm.put("opinions", opinions);
        return resultHm;
    }

    private List<String> getTopicOpinionIds(PublicOpinionTopic topic, TopicParameterVo parameterVo) {
        HashMap esSearchResult = getTopicOpinions(topic, parameterVo, null, null, parameterVo.getRepeatState());
        List<PoPublicOpinion> opinions = (List<PoPublicOpinion>) esSearchResult.get("opinions");
        List<String> ids = opinions.stream().map(PoPublicOpinion::getId).collect(Collectors.toList());
        return ids;
    }


    private List<String> getTopicOpinionIds(PublicOpinionTopic topic) {
        List<String> ids = new ArrayList<>();
        try {

            // 1、创建search请求
            SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);

            // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            //构造QueryBuilder
            QueryBuilder matchQueryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.matchQuery("title", topic.getRelatedWords()));

            sourceBuilder.query(matchQueryBuilder);

            searchRequest.source(sourceBuilder);

            //3、发送请求
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


            //4、处理响应
            if (RestStatus.OK.equals(searchResponse.status())) {
                //处理搜索命中文档结果
                SearchHits hits = searchResponse.getHits();
                TotalHits totalHits = hits.getTotalHits();

                sourceBuilder.query(matchQueryBuilder).from(0).size((int) totalHits.value);
                searchRequest.source(sourceBuilder);

                //3、发送请求
                searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
                hits = searchResponse.getHits();
                SearchHit[] searchHits = hits.getHits();

                for (SearchHit hit : searchHits) {
                    String index = hit.getIndex();
                    String type = hit.getType();
                    String id = hit.getId();
                    float score = hit.getScore();

                    String sourceAsString = hit.getSourceAsString(); //取成json串
                    PoPublicOpinion opinion = JSON.parseObject(sourceAsString, PoPublicOpinion.class);

                    //取_source字段值
                    //String sourceAsString = hit.getSourceAsString(); //取成json串
                    Map<String, Object> sourceAsMap = hit.getSourceAsMap(); // 取成map对象
                    //从map中取字段值
                /*String title = (String) sourceAsMap.get("title");
                String content  = (String) sourceAsMap.get("content"); */
                    //System.out.println("index:" + index + "  type:" + type + "  id:" + id);
                    //System.out.println("sourceMap : " +  sourceAsMap);
                    //取高亮结果
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    HighlightField highlight = highlightFields.get("title");
                    if (highlight != null) {
                        Text[] fragments = highlight.fragments();  //多值的字段会有多个值
                        if (fragments != null) {
                            String fragmentString = fragments[0].string();
                            //System.out.println("title highlight : " +  fragmentString);
                            //可用高亮字符串替换上面sourceAsMap中的对应字段返回到上一级调用
                            //sourceAsMap.put("title", fragmentString);
                            opinion.setTitle(fragments[0].string());
                        }
                    }

                    ids.add(opinion.getId());
                }
            }

        } catch (IOException e) {
            logger.error(e);
        }
        return ids;
    }


    /**
     * 根据主题Id查询舆情
     *
     * @param topicId
     * @return
     */
    public List<String> getMatchOpinionIdsByTopicId(Long topicId) {
        PublicOpinionTopic topic = publicOpinionTopicService.selectPublicOpinionTopicById(topicId);
        List<String> esMacthIds = getTopicOpinionIds(topic);
        Set<String> tmpSet = new HashSet<>(esMacthIds);
        return new ArrayList<>(tmpSet);
    }

    /**
     * 根据主题Id查询舆情
     *
     * @param topicId
     * @return
     */
    public List<String> getMatchOpinionIdsByTopicId(Long topicId, TopicParameterVo parameterVo) {
        PublicOpinionTopic topic = publicOpinionTopicService.selectPublicOpinionTopicById(topicId);
        List<String> esMacthIds = getTopicOpinionIds(topic, parameterVo);
        return esMacthIds;
    }

    public void deleteDocument(String index, Long[] ids) {
        BulkRequest bulkRequest = new BulkRequest();
        for (Long id : ids) {
            DeleteRequest deleteRequest = new DeleteRequest(index, id.toString());
            bulkRequest.add(deleteRequest);
        }


//        request.routing("routing");
//        request.timeout(TimeValue.timeValueMinutes(2));
////        request.timeout("2m");
//        request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
////        request.setRefreshPolicy("wait_for");
//        request.version(2);
//        request.versionType(VersionType.EXTERNAL);

        try {
            //DeleteResponse deleteResponse = client.bulk((bulkRequest, RequestOptions.DEFAULT);
            BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            if (bulkResponse.hasFailures()) {
                // 至少存在一个错误处理
                return;
            }
            //client.deleteAsync(request, RequestOptions.DEFAULT, listener);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ElasticsearchException exception) {
            if (exception.status() == RestStatus.CONFLICT) {
                //引发的异常表明返回了版本冲突错误
            }
        }
    }


    /**
     * 查询封装，返回ID集合--不分页
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<String> search(SearchSourceBuilder searchSourceBuilder) throws Exception {
        final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        searchSourceBuilder.fetchSource("id", "");
        searchSourceBuilder.size(10000);
        searchRequest.source(searchSourceBuilder);
        searchRequest.scroll(scroll);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        String scrollId = searchResponse.getScrollId();
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        long totalHits = searchResponse.getHits().getTotalHits().value;
        logger.info("es查询集合总数为{}", totalHits);

        // 封装集合
        List<String> list = new ArrayList<>();
        while (searchHits != null && searchHits.length > 0) {
            for (SearchHit hit : searchResponse.getHits().getHits()) {
                if (hit.getSourceAsMap().get("id") != null) {
                    String id = hit.getSourceAsMap().get("id").toString();
                    list.add(id);

                }
            }
            SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
            scrollRequest.scroll(scroll);
            searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT);
            scrollId = searchResponse.getScrollId();
            searchHits = searchResponse.getHits().getHits();
        }

        // 清除滚屏
        if (scrollId != null) {
            ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
            clearScrollRequest.addScrollId(scrollId);
            ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
            boolean succeeded = clearScrollResponse.isSucceeded();
        }


        return list;
    }


    /**
     * 查询封装，带分页
     *
     * @param searchSourceBuilder
     * @param pageNum
     * @param pageSize
     * @param s
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> PageInfo<T> search(SearchSourceBuilder searchSourceBuilder, Integer pageNum, Integer pageSize, Class<T> s) throws Exception {

        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        //分页
        if (pageNum != null && pageSize != null) {
            searchSourceBuilder.from((pageNum - 1) * pageSize);
            searchSourceBuilder.size(pageSize);
        }
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        JSONArray jsonArray = new JSONArray();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            JSONObject jsonObject = JSON.parseObject(sourceAsString);
            //取高亮结果
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields.get("content") != null) {
                jsonObject.put("content", highlightFields.get("content").fragments()[0].string());
            }
            if (highlightFields.get("title") != null) {
                jsonObject.put("title", highlightFields.get("title").fragments()[0].string());
            }
            jsonArray.add(jsonObject);
        }
        logger.info("返回总数为：" + hits.getTotalHits());
        int total = (int) hits.getTotalHits().value;
        // 封装分页
        List<T> list = jsonArray.toJavaList(s);
        PageInfo<T> page = new PageInfo<>();
        page.setList(list);
        page.setPageNum(pageNum);
        page.setPageSize(pageSize);
        page.setTotal(total);
        page.setPages(total == 0 ? 0 : (total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1));
        page.setHasNextPage(page.getPageNum() < page.getPages());
        return page;
    }

    /**
     * 批量插入关键字
     *
     * @param keywords
     */

    public void indexBatchKeyWords(List<OpinionKeyword> keywords) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            // 1、创建索引请求
            for (OpinionKeyword keyword : keywords) {
                IndexRequest request = new IndexRequest(
                        EsIndex.OPINION_KEYWORD);   //索引
                if (StringUtils.isEmpty(keyword.getOpinionId())) {
                    keyword.setOpinionId(UUID.randomUUID().toString());
                }
                request.id(keyword.getOpinionId());
                // 2、准备文档数据
                // 方式一：直接给JSON串
                System.out.println(JSONObject.toJSONString(keyword));

                request.source(JSONObject.toJSONString(keyword), XContentType.JSON);

                bulkRequest.add(request);
            }


            //4、发送请求
            BulkResponse bulkResponse = null;
            try {
                // 同步方式
                bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (bulkResponse != null) {

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量插入关联人物
     *
     * @param keywords
     */

    public void indexBatchPersons(List<OpinionPerson> keywords) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            // 1、创建索引请求
            for (OpinionPerson keyword : keywords) {
                IndexRequest request = new IndexRequest(
                        EsIndex.OPINION_PERSON);   //索引
                if (StringUtils.isEmpty(keyword.getOpinionId())) {
                    keyword.setOpinionId(UUID.randomUUID().toString());
                }
                request.id(keyword.getOpinionId());
                // 2、准备文档数据
                // 方式一：直接给JSON串
                System.out.println(JSONObject.toJSONString(keyword));

                request.source(JSONObject.toJSONString(keyword), XContentType.JSON);

                bulkRequest.add(request);
            }


            //4、发送请求
            BulkResponse bulkResponse = null;
            try {
                // 同步方式
                bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (bulkResponse != null) {

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量插入关联地域
     *
     * @param keywords
     */

    public void indexBatchLocations(List<OpinionLocation> keywords) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            // 1、创建索引请求
            for (OpinionLocation keyword : keywords) {
                IndexRequest request = new IndexRequest(
                        EsIndex.OPINION_LOCATION);   //索引
                if (StringUtils.isEmpty(keyword.getOpinionId())) {
                    keyword.setOpinionId(UUID.randomUUID().toString());
                }
                request.id(keyword.getOpinionId());
                // 2、准备文档数据
                // 方式一：直接给JSON串
                System.out.println(JSONObject.toJSONString(keyword));

                request.source(JSONObject.toJSONString(keyword), XContentType.JSON);

                bulkRequest.add(request);
            }


            //4、发送请求
            BulkResponse bulkResponse = null;
            try {
                // 同步方式
                bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (bulkResponse != null) {

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 批量插入关联机构
     *
     * @param keywords
     */

    public void indexBatchOrganizations(List<OpinionOrganization> keywords) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            // 1、创建索引请求
            for (OpinionOrganization keyword : keywords) {
                IndexRequest request = new IndexRequest(
                        EsIndex.OPINION_ORGANIZATION);   //索引
                if (StringUtils.isEmpty(keyword.getOpinionId())) {
                    keyword.setOpinionId(UUID.randomUUID().toString());
                }
                request.id(keyword.getOpinionId());
                // 2、准备文档数据
                // 方式一：直接给JSON串
                System.out.println(JSONObject.toJSONString(keyword));

                request.source(JSONObject.toJSONString(keyword), XContentType.JSON);

                bulkRequest.add(request);
            }


            //4、发送请求
            BulkResponse bulkResponse = null;
            try {
                // 同步方式
                bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (bulkResponse != null) {

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void indexBatchOpinion(List<PoPublicOpinion> opinionList) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            // 1、创建索引请求
            for (PoPublicOpinion opinion : opinionList) {
                IndexRequest request = new IndexRequest(
                        EsIndex.OPINION);   //索引
                if (StringUtils.isEmpty(opinion.getId())) {
                    opinion.setId(UUID.randomUUID().toString());
                }
                request.id(opinion.getId());
                // 2、准备文档数据
                // 方式一：直接给JSON串
                System.out.println(JSONObject.toJSONString(opinion));

                request.source(JSONObject.toJSONString(opinion), XContentType.JSON);

                bulkRequest.add(request);
            }

            //4、发送请求
            BulkResponse bulkResponse = null;
            try {
                // 同步方式
                bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (bulkResponse != null) {

            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 高亮
     *
     * @param event
     * @param parameter
     * @param bindIds
     * @return
     */
    public SearchSourceBuilder buildSearchSourceBuilder(PublicOpinionEvents event, EventParameterVo parameter, List<String> bindIds) {

        //用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder matchQueryBuilder = buildBoolQueryBuilder(event, parameter, bindIds);
        sourceBuilder.query(matchQueryBuilder);

        // 高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        highlightBuilder.field("title");      //高亮查询字段
        highlightBuilder.field("content");      //高亮查询字段
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<strong><font color=\"#FF0000\">");   //高亮设置
        highlightBuilder.postTags("</font></strong>");
        sourceBuilder.highlighter(highlightBuilder);

        //排序
        if (parameter != null) {
            if (parameter.getSort() != null && parameter.getSort().equals("desc")) {
                List<SortBuilder<?>> sorts = new ArrayList<>();
                SortBuilder sortBuilder = SortBuilders.fieldSort("publishTime").order(SortOrder.DESC);
                sorts.add(sortBuilder);
                sourceBuilder.sort(sorts);
            } else if (parameter.getSort() != null && parameter.getSort().equals("asc")) {
                List<SortBuilder<?>> sorts = new ArrayList<>();
                SortBuilder sortBuilder = SortBuilders.fieldSort("publishTime").order(SortOrder.ASC);
                sorts.add(sortBuilder);
                sourceBuilder.sort(sorts);
            }
        }
        return sourceBuilder;
    }


    /**
     * 主题构建查询
     *
     * @param topic
     * @param parameterVo
     * @param pageNum
     * @param pageSize
     * @return
     */
    SearchSourceBuilder buildSearchSourceBuilder(PublicOpinionTopic topic, TopicParameterVo parameterVo, Integer pageNum, Integer pageSize) {

        // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //构造QueryBuilder
        BoolQueryBuilder matchQueryBuilder = QueryBuilders.boolQuery();

        //关键词，舆情词，排除词
        matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, topic.getSearchArea(), topic.getRelatedWords(), topic.getOpinionWords(), topic.getExclusionWords());


        if (parameterVo != null) {
            if (parameterVo.getRepeatState() != null && parameterVo.getRepeatState()) {
                CollapseBuilder collapseBuilder = new CollapseBuilder("url");
                sourceBuilder.collapse(collapseBuilder);
            }
            //前端提交测关键词和查询区域
            if (StringUtils.isNotEmpty(parameterVo.getKeyWords())) {
                if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("title")) {
                    matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("title", parameterVo.getKeyWords()));
                } else if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("content")) {
                    matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("content", parameterVo.getKeyWords()));
                } else {
                    matchQueryBuilder.must(QueryBuilders.multiMatchQuery(parameterVo.getKeyWords(), "title", "content").type(MultiMatchQueryBuilder.Type.PHRASE));
                }
            }
            //查询的时间段
            if (StringUtils.isNotEmpty(parameterVo.getTimeType()) && !parameterVo.getTimeType().equals("all")) {
                HashMap hashMap = DateUtils.getStartEndTime(parameterVo.getTimeType(), parameterVo.getStartDateTime(), parameterVo.getEndDateTime());
                Date beginPublishDay = (Date) hashMap.get("beginPublishDay");
                Date endPublishDay = (Date) hashMap.get("endPublishDay");
                matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, beginPublishDay, endPublishDay);
            }

            //媒体类型
            if (parameterVo.getMediaType() != null && parameterVo.getMediaType().size() > 0) {
                List<String> mediaNames = new ArrayList<>();
                for (String mediaType : parameterVo.getMediaType()) {
                    if (mediaType.equals("microBlog")) {
                        mediaNames.add("微博");
                    } else if (mediaType.equals("weChat")) {
                        mediaNames.add("微信");
                    } else if (mediaType.equals("postsBar")) {
                        mediaNames.add("百度百家");
                        mediaNames.add("百度贴吧");
                    } else if (mediaType.equals("electronicNewspaper")) {
                        mediaNames.add("项目可行性研究中");
                    } else if (mediaType.equals("video")) {
                        mediaNames.add("bilibili");
                        mediaNames.add("新浪微博视频");
                    } else if (mediaType.equals("news")) {
                        mediaNames.add("搜狐新闻");
                        mediaNames.add("网易新闻");
                        mediaNames.add("凤凰网");
                        mediaNames.add("玉溪日报");
                        mediaNames.add("现代快报");
                    } else if (mediaType.equals("forum")) {
                        mediaNames.add("飘仙建站");

                    } else if (mediaType.equals("blog")) {

                    } else if (mediaType.equals("app")) {
                        mediaNames.add("今日头条");
                        mediaNames.add("UC头条");
                        mediaNames.add("小红书");
                    } else if (mediaType.equals("interLocution")) {
                        mediaNames.add("知乎专栏");
                        mediaNames.add("知乎");
                    } else if (mediaType.equals("shortVideo")) {
                        mediaNames.add("抖音app");
                        mediaNames.add("快手app");
                    }
                }
                //媒体名称
                if (mediaNames.size() > 0) {
                    matchQueryBuilder.must(QueryBuilders.termsQuery("siteName", mediaNames));
                }

            }
            //情感态度
            if (parameterVo.getIspositive() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("ispositive", parameterVo.getIspositive()));
            }
            if (parameterVo.getIsneutral() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("isneutral", parameterVo.getIsneutral()));
            }
            if (parameterVo.getIsnegative() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("isnegative", parameterVo.getIsnegative()));
            }


            if (parameterVo.getIsEmotionalAnalysis() != null) {
                if (parameterVo.getIsEmotionalAnalysis()) {
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isLike"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isHate"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isHappy"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isGrief"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isFear"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isAnger"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isAmaze"));
                    matchQueryBuilder.should(QueryBuilders.termQuery("judged", 1));
                    matchQueryBuilder.minimumShouldMatch(1);
                } else {
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isLike"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isHate"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isHappy"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isGrief"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isFear"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isAnger"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isAmaze"));
                    matchQueryBuilder.mustNot(QueryBuilders.termQuery("judged", 1));
                }
            }

        }


        sourceBuilder.query(matchQueryBuilder);
        if (pageNum != null && pageSize != null) {
            sourceBuilder.from((pageNum - 1) * pageSize);
            sourceBuilder.size(pageSize);
        }

        // 高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        highlightBuilder.field("title");      //高亮查询字段
        highlightBuilder.field("content");      //高亮查询字段
        highlightBuilder.field("relatedWords");      //高亮查询字段
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<font color=\"#FF0000\">");   //高亮设置
        highlightBuilder.postTags("</font>");
        sourceBuilder.highlighter(highlightBuilder);

        return sourceBuilder;
    }


    /**
     * 事件构建查询
     *
     * @param event
     * @param parameterVo
     * @param pageNum
     * @param pageSize
     * @return
     */
    SearchSourceBuilder buildSearchSourceBuilder(PublicOpinionEvents event, TopicParameterVo parameterVo, Integer pageNum, Integer pageSize) {

        // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //构造QueryBuilder
        BoolQueryBuilder matchQueryBuilder = QueryBuilders.boolQuery();

        //关键词，舆情词，排除词
        matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, event.getSearchArea(), event.getRelatedWords(), event.getOpinionWords(), event.getExclusionWords());
        //时间范围
        matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, event.getStartTime(), event.getEndTime());

        if (parameterVo != null) {

            if (parameterVo.getRepeatState() != null && parameterVo.getRepeatState()) {
                CollapseBuilder collapseBuilder = new CollapseBuilder("url");
                sourceBuilder.collapse(collapseBuilder);
            }
            //前端提交测关键词和查询区域
            if (StringUtils.isNotEmpty(parameterVo.getKeyWords())) {
                if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("title")) {
                    matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("title", parameterVo.getKeyWords()));
                } else if (StringUtils.isNotEmpty(parameterVo.getSearchArea()) && parameterVo.getSearchArea().equals("content")) {
                    matchQueryBuilder.must(QueryBuilders.matchPhraseQuery("content", parameterVo.getKeyWords()));
                } else {
                    matchQueryBuilder.must(QueryBuilders.multiMatchQuery(parameterVo.getKeyWords(), "title", "content").type(MultiMatchQueryBuilder.Type.PHRASE));
                }
            }
            //查询的时间段
            if (StringUtils.isNotEmpty(parameterVo.getTimeType()) && !parameterVo.getTimeType().equals("all")) {
                HashMap hashMap = DateUtils.getStartEndTime(parameterVo.getTimeType(), parameterVo.getStartDateTime(), parameterVo.getEndDateTime());
                Date beginPublishDay = (Date) hashMap.get("beginPublishDay");
                Date endPublishDay = (Date) hashMap.get("endPublishDay");
                matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, beginPublishDay, endPublishDay);
            }

            //媒体类型
            if (parameterVo.getMediaType() != null && parameterVo.getMediaType().size() > 0) {
                List<String> mediaNames = new ArrayList<>();
                for (String mediaType : parameterVo.getMediaType()) {
                    if (mediaType.equals("microBlog")) {
                        mediaNames.add("微博");
                    } else if (mediaType.equals("weChat")) {
                        mediaNames.add("微信");
                    } else if (mediaType.equals("postsBar")) {
                        mediaNames.add("百度百家");
                        mediaNames.add("百度贴吧");
                    } else if (mediaType.equals("electronicNewspaper")) {
                        mediaNames.add("项目可行性研究中");
                    } else if (mediaType.equals("video")) {
                        mediaNames.add("bilibili");
                        mediaNames.add("新浪微博视频");
                    } else if (mediaType.equals("news")) {
                        mediaNames.add("搜狐新闻");
                        mediaNames.add("网易新闻");
                        mediaNames.add("凤凰网");
                        mediaNames.add("玉溪日报");
                        mediaNames.add("现代快报");
                    } else if (mediaType.equals("forum")) {
                        mediaNames.add("飘仙建站");

                    } else if (mediaType.equals("blog")) {

                    } else if (mediaType.equals("app")) {
                        mediaNames.add("今日头条");
                        mediaNames.add("UC头条");
                        mediaNames.add("小红书");
                    } else if (mediaType.equals("interLocution")) {
                        mediaNames.add("知乎专栏");
                        mediaNames.add("知乎");
                    } else if (mediaType.equals("shortVideo")) {
                        mediaNames.add("抖音app");
                        mediaNames.add("快手app");
                    }
                }
                //媒体名称
                if (mediaNames.size() > 0) {
                    matchQueryBuilder.must(QueryBuilders.termsQuery("siteName", mediaNames));
                }

            }
            //情感态度
            if (parameterVo.getIspositive() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("ispositive", parameterVo.getIspositive()));
            }
            if (parameterVo.getIsneutral() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("isneutral", parameterVo.getIsneutral()));
            }
            if (parameterVo.getIsnegative() == 1) {
                matchQueryBuilder.must(QueryBuilders.termQuery("isnegative", parameterVo.getIsnegative()));
            }


            if (parameterVo.getIsEmotionalAnalysis() != null) {
                if (parameterVo.getIsEmotionalAnalysis()) {
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isLike"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isHate"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isHappy"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isGrief"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isFear"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isAnger"));
                    matchQueryBuilder.should(QueryBuilders.existsQuery("isAmaze"));
                    matchQueryBuilder.should(QueryBuilders.termQuery("judged", 1));
                    matchQueryBuilder.minimumShouldMatch(1);
                } else {
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isLike"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isHate"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isHappy"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isGrief"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isFear"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isAnger"));
                    matchQueryBuilder.mustNot(QueryBuilders.existsQuery("isAmaze"));
                    matchQueryBuilder.mustNot(QueryBuilders.termQuery("judged", 1));
                }
            }

        }


        sourceBuilder.query(matchQueryBuilder);
        if (pageNum != null && pageSize != null) {
            sourceBuilder.from((pageNum - 1) * pageSize);
            sourceBuilder.size(pageSize);
        }

        // 高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        highlightBuilder.field("title");      //高亮查询字段
        highlightBuilder.field("content");      //高亮查询字段
        highlightBuilder.field("relatedWords");      //高亮查询字段
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<font color=\"#FF0000\">");   //高亮设置
        highlightBuilder.postTags("</font>");
        sourceBuilder.highlighter(highlightBuilder);

        return sourceBuilder;
    }

    /**
     * 构建基于事件、查询参数、绑定舆情、排除舆情的查询语句
     *
     * @param event
     * @param parameter
     * @param bindIds
     * @param excludeIds
     * @return
     */
    public BoolQueryBuilder buildBoolQueryBuilder(PublicOpinionEvents event, EventParameterVo parameter, List<String> bindIds, List<String> excludeIds) {
        BoolQueryBuilder queryBuilder = buildBoolQueryBuilder(event, parameter, bindIds);
        if (excludeIds != null && excludeIds.size() > 0) {
            queryBuilder.mustNot(QueryBuilders.termsQuery("id", excludeIds));
        }
        return queryBuilder;
    }


    /**
     * 构建基于事件、查询参数、绑定舆情的查询语句
     *
     * @param event
     * @param parameter
     * @param bindIds
     * @return
     */
    public BoolQueryBuilder buildBoolQueryBuilder(PublicOpinionEvents event, EventParameterVo parameter, List<String> bindIds) {
        //构造QueryBuilder
        BoolQueryBuilder matchQueryBuilder = QueryBuilders.boolQuery();
        if (event != null) {
            if (event.getStartTime() != null && event.getEndTime() != null) {
                matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, event.getStartTime(), event.getEndTime());
            } else if (event.getStartTime() != null) {
                matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilderStartTime(matchQueryBuilder, event.getStartTime());
            } else if (event.getEndTime() != null) {
                matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilderEndTime(matchQueryBuilder, event.getEndTime());
            }
            //绑定的舆情
            if (bindIds != null && bindIds.size() > 0) {
                matchQueryBuilder.should(QueryBuilders.termsQuery("id", bindIds));
            }
            matchQueryBuilder = elasticsearchQueryBuilderService.boolQueryBuilder(matchQueryBuilder, event.getSearchArea(), event.getRelatedWords(), event.getOpinionWords(), event.getExclusionWords());

        }
        //前端过滤
        if (parameter != null) {
            matchQueryBuilder = buildBoolQueryBuilder(matchQueryBuilder, parameter);
            //媒体类型过滤
            if (parameter.getMediaType() != null && parameter.getMediaType().size() > 0) {
                matchQueryBuilder.must(QueryBuilders.termsQuery("carrie", parameter.getMediaType()));
            }

        }

        return matchQueryBuilder;
    }


    /**
     * 查询封装，返回指定个数
     *
     * @param searchSourceBuilder
     * @param s
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> List<T> search(SearchSourceBuilder searchSourceBuilder, Class<T> s, int count) throws Exception {
        searchSourceBuilder.size(count);
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


        SearchHit[] searchHits = searchResponse.getHits().getHits();
        long totalHits = searchResponse.getHits().getTotalHits().value;
        logger.info("es查询集合总数为{}", totalHits);

        JSONArray jsonArray = new JSONArray();

        for (SearchHit hit : searchHits) {
            String sourceAsString = hit.getSourceAsString();
            JSONObject jsonObject = JSON.parseObject(sourceAsString);
            jsonArray.add(jsonObject);
        }

        // 封装集合
        List<T> list = jsonArray.toJavaList(s);
        return list;
    }


    /**
     * 查询封装，返回指定个数
     *
     * @param searchSourceBuilder
     * @param s
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> List<T> searchRemoveDuplicates(SearchSourceBuilder searchSourceBuilder, Class<T> s, int count) throws Exception {
        searchSourceBuilder.size(count);
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        SearchHit[] searchHits = searchResponse.getHits().getHits();
        long totalHits = searchResponse.getHits().getTotalHits().value;
        logger.info("es查询集合总数为{}", totalHits);

        JSONArray jsonArray = new JSONArray();

        for (SearchHit hit : searchHits) {
            String sourceAsString = hit.getSourceAsString();
            JSONObject jsonObject = JSON.parseObject(sourceAsString);
            jsonArray.add(jsonObject);
        }

        // 封装集合
        List<T> list = jsonArray.toJavaList(s);
        return list;
    }


    /**
     * 获取所有舆情数量
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public Long getAllOpinionCount(SearchSourceBuilder searchSourceBuilder) {
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        searchSourceBuilder.trackTotalHits(true);
        searchRequest.source(searchSourceBuilder);
        Long total = 0L;
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            total = search.getHits().getTotalHits().value;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return total;

    }


    /**
     * 按媒体类型、情感分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameListValue> getCountGroupByMediaTypeAndSensitiveInformation(SearchSourceBuilder searchSourceBuilder) throws IOException {
        List<NameListValue> nameListValues = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("媒体类型").field("carrie");
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id.keyword");

        TermsAggregationBuilder negativeAggregationBuilder = AggregationBuilders.terms("isnegative").field("isnegative");
        negativeAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder neutralAggregationBuilder = AggregationBuilders.terms("isneutral").field("isneutral");
        neutralAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder positiveAggregationBuilder = AggregationBuilders.terms("ispositive").field("ispositive");
        positiveAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(negativeAggregationBuilder).subAggregation(neutralAggregationBuilder).subAggregation(positiveAggregationBuilder);

        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);

        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        //下面获得聚合查询
        Aggregations aggregations = search.getAggregations();
        for (Aggregation a : aggregations) {
            Terms t = (Terms) a;
            for (Terms.Bucket bucket : t.getBuckets()) {


                List<NameValue> list = new ArrayList<>();
                Aggregation positiveAggregation = bucket.getAggregations().asMap().get("ispositive");
                Terms positiveTerms = (Terms) positiveAggregation;

                for (Terms.Bucket b : positiveTerms.getBuckets()) {
                    if (b.getKey().toString().equals("1")) {
                        long value = b.getDocCount();
                        NameValue nameValue = new NameValue();
                        nameValue.setName("ispositive");
                        nameValue.setValue((int) value);
                        list.add(nameValue);

                    }
                }

                Aggregation neutralAggregation = bucket.getAggregations().asMap().get("isneutral");
                Terms neutralTerms = (Terms) neutralAggregation;

                for (Terms.Bucket b : neutralTerms.getBuckets()) {
                    if (b.getKey().toString().equals("1")) {
                        long value = b.getDocCount();
                        NameValue nameValue = new NameValue();
                        nameValue.setName("isneutral");
                        nameValue.setValue((int) value);
                        list.add(nameValue);
                    }
                }

                Aggregation negativeAggregation = bucket.getAggregations().asMap().get("isnegative");
                Terms negativeTerms = (Terms) negativeAggregation;
                for (Terms.Bucket b : negativeTerms.getBuckets()) {
                    if (b.getKey().toString().equals("1")) {
                        long value = b.getDocCount();
                        NameValue nameValue = new NameValue();
                        nameValue.setName("isnegative");
                        nameValue.setValue((int) value);
                        list.add(nameValue);
                    }
                }

                NameListValue nameListValue = new NameListValue();
                int carrie = Integer.parseInt(bucket.getKey().toString());
                nameListValue.setName(ChinaMediaTypeEnum.getNameByCarrie(carrie));
                nameListValue.setValue(list);
                nameListValues.add(nameListValue);

            }
        }
        return nameListValues;
    }


    /**
     * 按日期、时间分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameListValue> getCountGroupByPublishDateAndPublishTime(SearchSourceBuilder searchSourceBuilder) throws IOException {
        List<NameListValue> nameListValues = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders.dateHistogram("publishDate").format("yyyy-MM-dd").field("publishTime").calendarInterval(DateHistogramInterval.DAY);//.timeZone(ZoneId.of("Asia/Shanghai")
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        DateHistogramAggregationBuilder timeAggregationBuilder = AggregationBuilders.dateHistogram("publishTime").format("HH").field("publishTime").calendarInterval(DateHistogramInterval.HOUR);
        timeAggregationBuilder.subAggregation(valueCountAggregationBuilder);
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = aggregationBuilder.subAggregation(timeAggregationBuilder);

        searchSourceBuilder.aggregation(dateHistogramAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        //下面获得聚合查询
        Aggregations aggregations = search.getAggregations();
        for (Aggregation a : aggregations) {
            Histogram histogram = (Histogram) a;
            for (Histogram.Bucket bucket : histogram.getBuckets()) {
                for (Aggregation b : bucket.getAggregations()) {
                    Histogram histogramSon = (Histogram) b;
                    List<NameValue> list = new ArrayList<>();
                    for (Histogram.Bucket bucket1 : histogramSon.getBuckets()) {
                        ValueCount count = (ValueCount) bucket1.getAggregations().asMap().get("count");
                        long value = count.getValue();
                        NameValue nameValue = new NameValue();
                        nameValue.setName(DateUtils.zonedDateTimeToString((ZonedDateTime) bucket1.getKey(), "HH"));
                        nameValue.setValue((int) value);
                        list.add(nameValue);
                    }
                    NameListValue nameListValue = new NameListValue();
                    nameListValue.setName(DateUtils.zonedDateTimeToString((ZonedDateTime) bucket.getKey(), DateUtils.YYYY_MM_DD));
                    nameListValue.setValue(list);
                    nameListValues.add(nameListValue);
                }
            }
        }

        return nameListValues;
    }


    /**
     * 按日期、媒体名称分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameListValue> getCountGroupByPublishDateAndMediaName(SearchSourceBuilder searchSourceBuilder) throws IOException {
        List<NameListValue> nameListValues = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders.dateHistogram("publishDate").format("yyyy-MM-dd").field("publishTime").calendarInterval(DateHistogramInterval.DAY);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder sensitiveInformationAggregationBuilder = AggregationBuilders.terms("媒体名称").field("siteName");
        sensitiveInformationAggregationBuilder.subAggregation(valueCountAggregationBuilder);
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = aggregationBuilder.subAggregation(sensitiveInformationAggregationBuilder);

        searchSourceBuilder.aggregation(dateHistogramAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        //下面获得聚合查询
        Aggregations aggregations = search.getAggregations();
        for (Aggregation a : aggregations) {
            Histogram histogram = (Histogram) a;
            for (Histogram.Bucket bucket : histogram.getBuckets()) {
                for (Aggregation b : bucket.getAggregations()) {
                    Terms terms = (Terms) b;
                    List<NameValue> list = new ArrayList<>();
                    for (Terms.Bucket bucket1 : terms.getBuckets()) {
                        ValueCount count = (ValueCount) bucket1.getAggregations().asMap().get("count");
                        long value = count.getValue();
                        NameValue nameValue = new NameValue();
                        nameValue.setName(bucket1.getKey().toString());
                        nameValue.setValue((int) value);
                        list.add(nameValue);
                    }
                    NameListValue nameListValue = new NameListValue();
                    nameListValue.setName(DateUtils.getZonedDateTimetoString((ZonedDateTime) bucket.getKey(), DateUtils.YYYY_MM_DD));
                    nameListValue.setValue(list);
                    nameListValues.add(nameListValue);
                }
            }
        }
        return nameListValues;
    }


    /**
     * 按日期、媒体类型分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameListValue> getCountGroupByPublishDateAndMediaType(SearchSourceBuilder searchSourceBuilder) {
        List<NameListValue> nameListValues = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders.dateHistogram("publishDate").format("yyyy-MM-dd").field("publishTime").calendarInterval(DateHistogramInterval.DAY);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder sensitiveInformationAggregationBuilder = AggregationBuilders.terms("媒体类型").field("carrie");
        sensitiveInformationAggregationBuilder.subAggregation(valueCountAggregationBuilder);
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = aggregationBuilder.subAggregation(sensitiveInformationAggregationBuilder);

        searchSourceBuilder.aggregation(dateHistogramAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Histogram histogram = (Histogram) a;
                for (Histogram.Bucket bucket : histogram.getBuckets()) {
                    for (Aggregation b : bucket.getAggregations()) {
                        Terms terms = (Terms) b;
                        List<NameValue> list = new ArrayList<>();
                        for (Terms.Bucket bucket1 : terms.getBuckets()) {
                            ValueCount count = (ValueCount) bucket1.getAggregations().asMap().get("count");
                            long value = count.getValue();
                            NameValue nameValue = new NameValue();
                            int carrie = Integer.parseInt(bucket1.getKey().toString());
                            nameValue.setName(ChinaMediaTypeEnum.getNameByCarrie(carrie));
                            nameValue.setValue((int) value);
                            list.add(nameValue);
                        }
                        NameListValue nameListValue = new NameListValue();
                        nameListValue.setName(DateUtils.getZonedDateTimetoString((ZonedDateTime) bucket.getKey(), DateUtils.YYYY_MM_DD));
                        nameListValue.setValue(list);
                        nameListValues.add(nameListValue);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return nameListValues;
    }


    /**
     * 按媒体名称分组，获取情感数量
     *
     * @param searchSourceBuilder
     * @return
     */
    public List<OpMediaNameSensitiveDayNumVM> getCountSensitiveOpinionByMediaName(SearchSourceBuilder searchSourceBuilder) {
        List<OpMediaNameSensitiveDayNumVM> nameListValues = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("媒体名称").field("siteName");
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");

        TermsAggregationBuilder negativeAggregationBuilder = AggregationBuilders.terms("isnegative").field("isnegative");
        negativeAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder neutralAggregationBuilder = AggregationBuilders.terms("isneutral").field("isneutral");
        neutralAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder positiveAggregationBuilder = AggregationBuilders.terms("ispositive").field("ispositive");
        positiveAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(negativeAggregationBuilder).subAggregation(neutralAggregationBuilder).subAggregation(positiveAggregationBuilder);

        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);

        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms t = (Terms) a;
                for (Terms.Bucket bucket : t.getBuckets()) {


                    OpMediaNameSensitiveDayNumVM nameListValue = new OpMediaNameSensitiveDayNumVM();
                    nameListValue.setMediaName(bucket.getKey().toString());

                    Aggregation positiveAggregation = bucket.getAggregations().asMap().get("ispositive");
                    Terms positiveTerms = (Terms) positiveAggregation;

                    for (Terms.Bucket b : positiveTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            nameListValue.setPositive(value);

                        }
                    }

                    Aggregation neutralAggregation = bucket.getAggregations().asMap().get("isneutral");
                    Terms neutralTerms = (Terms) neutralAggregation;

                    for (Terms.Bucket b : neutralTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            nameListValue.setNeutral(value);
                        }
                    }

                    Aggregation negativeAggregation = bucket.getAggregations().asMap().get("isnegative");
                    Terms negativeTerms = (Terms) negativeAggregation;
                    for (Terms.Bucket b : negativeTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            nameListValue.setNegative(value);
                        }
                    }

                    nameListValues.add(nameListValue);


                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return nameListValues;
    }


    /**
     * 按作者分组，获取情感数量
     *
     * @param searchSourceBuilder
     * @return
     */
    public List<OpAuthorSensitiveDayNumVM> getCountSensitiveOpinionByAuthor(SearchSourceBuilder searchSourceBuilder) {
        List<OpAuthorSensitiveDayNumVM> nameListValues = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("作者").field("author");
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id.keyword");

        TermsAggregationBuilder negativeAggregationBuilder = AggregationBuilders.terms("isnegative").field("isnegative");
        negativeAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder neutralAggregationBuilder = AggregationBuilders.terms("isneutral").field("isneutral");
        neutralAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder positiveAggregationBuilder = AggregationBuilders.terms("ispositive").field("ispositive");
        positiveAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(negativeAggregationBuilder).subAggregation(neutralAggregationBuilder).subAggregation(positiveAggregationBuilder);

        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);

        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms t = (Terms) a;
                for (Terms.Bucket bucket : t.getBuckets()) {


                    OpAuthorSensitiveDayNumVM nameListValue = new OpAuthorSensitiveDayNumVM();
                    nameListValue.setAuthor(bucket.getKey().toString());
                    nameListValue.setCount(bucket.getDocCount());
                    Aggregation positiveAggregation = bucket.getAggregations().asMap().get("ispositive");
                    Terms positiveTerms = (Terms) positiveAggregation;

                    for (Terms.Bucket b : positiveTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            nameListValue.setPositive(value);

                        }
                    }

                    Aggregation neutralAggregation = bucket.getAggregations().asMap().get("isneutral");
                    Terms neutralTerms = (Terms) neutralAggregation;

                    for (Terms.Bucket b : neutralTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            nameListValue.setNeutral(value);
                        }
                    }

                    Aggregation negativeAggregation = bucket.getAggregations().asMap().get("isnegative");
                    Terms negativeTerms = (Terms) negativeAggregation;
                    for (Terms.Bucket b : negativeTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            nameListValue.setNegative(value);
                        }
                    }

                    nameListValues.add(nameListValue);


                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return nameListValues;
    }


    /**
     * 按照日期分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameValue> getCountGroupByPublishDate(SearchSourceBuilder searchSourceBuilder) {
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders.dateHistogram("publishDate").format("yyyy-MM-dd").field("publishTime").calendarInterval(DateHistogramInterval.DAY);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(dateHistogramAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Histogram histogram = (Histogram) a;
                for (Histogram.Bucket bucket : histogram.getBuckets()) {
                    ValueCount count = (ValueCount) bucket.getAggregations().asMap().get("count");
                    long value = count.getValue();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(DateUtils.getZonedDateTimetoString((ZonedDateTime) bucket.getKey(), DateUtils.YYYY_MM_DD));
                    nameValue.setValue((int) value);
                    list.add(nameValue);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 根据媒体类型分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameValue> getCountGroupByMediaType(SearchSourceBuilder searchSourceBuilder) throws IOException {
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("媒体类型").field("carrie");
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        //下面获得聚合查询
        Aggregations aggregations = search.getAggregations();
        for (Aggregation a : aggregations) {
            Terms terms = (Terms) a;
            for (Terms.Bucket bucket : terms.getBuckets()) {
                ValueCount count = (ValueCount) bucket.getAggregations().asMap().get("count");
                long value = count.getValue();
                NameValue nameValue = new NameValue();
                int carrie = Integer.parseInt(bucket.getKey().toString());
                nameValue.setName(ChinaMediaTypeEnum.getNameByCarrie(carrie));
                nameValue.setValue((int) value);
                list.add(nameValue);
            }
        }
        return list;
    }


    /**
     * 根据媒体名称分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameValue> getCountGroupByMediaName(SearchSourceBuilder searchSourceBuilder) {
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("媒体名称").field("siteName").size(500);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    ValueCount count = (ValueCount) bucket.getAggregations().asMap().get("count");
                    long value = count.getValue();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(bucket.getKey().toString());
                    nameValue.setValue((int) value);
                    list.add(nameValue);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;

    }


    /**
     * 根据媒体名称分组并取publishDate最新的一条
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<PoPublicOpinion> getCountGroupByMediaNameOrderByPublishDate(SearchSourceBuilder searchSourceBuilder) throws IOException {
        List<PoPublicOpinion> opinions = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }

        // 创建聚合
        TermsAggregationBuilder termsAggregation = AggregationBuilders.terms("sites")
                .field("siteName")
                .subAggregation(AggregationBuilders.min("earliest_publish_time").field("publishTime"))
                .subAggregation(AggregationBuilders.topHits("top_hits")
                        .size(1)
                        .sort("publishTime", SortOrder.ASC)
                        .fetchSource(new String[]{"title", "publishTime", "siteName", "id", "url", "carrie"}, null));

        // 将聚合添加到搜索请求中
        searchSourceBuilder.aggregation(termsAggregation);
        searchRequest.source(searchSourceBuilder);

        try {
            // 执行搜索请求
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

            // 处理聚合结果
            Terms termsAggregationResult = searchResponse.getAggregations().get("sites");
            for (Terms.Bucket bucket : termsAggregationResult.getBuckets()) {
                String siteName = bucket.getKeyAsString();

                Min minAggregationResult = bucket.getAggregations().get("earliest_publish_time");
                long earliestPublishTime = (long) minAggregationResult.getValue();

                System.out.println("Site Name: " + siteName);
                System.out.println("Earliest Publish Time: " + earliestPublishTime);
                // 获取cleanTitle和content字段的值
                TopHits topHitsAggregationResult = bucket.getAggregations().get("top_hits");
                SearchHits searchHits = topHitsAggregationResult.getHits();
                for (SearchHit hit : searchHits.getHits()) {
                    String sourceAsString = hit.getSourceAsString(); //取成json串
                    PoPublicOpinion opinion = JSON.parseObject(sourceAsString, PoPublicOpinion.class);
                    //载体编码转为载体名称
                    int carrie = Integer.parseInt(opinion.getCarrie());
                    opinion.setCarrie(ChinaMediaTypeEnum.getNameByCarrie(carrie));
                    opinions.add(opinion);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


        // 根据publishTime属性重新排序
        Collections.sort(opinions, Comparator.comparingLong(o -> o.getPublishTime().getTime()));
        return opinions;
    }


    /**
     * 根据媒体作者分组
     *
     * @param searchSourceBuilder
     * @return
     * @throws IOException
     */
    public List<NameValue> getCountGroupByAuthor(SearchSourceBuilder searchSourceBuilder) {
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("作者").field("author").size(500);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    ValueCount count = (ValueCount) bucket.getAggregations().asMap().get("count");
                    long value = count.getValue();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(bucket.getKey().toString());
                    nameValue.setValue((int) value);
                    if (!bucket.getKey().toString().equals("无") && !bucket.getKey().toString().equals("")) {
                        list.add(nameValue);
                    }

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取关键词词频
     *
     * @param searchSourceBuilder
     * @param size
     * @return
     */
    public List<NameValue> getCountGroupByKeywords(SearchSourceBuilder searchSourceBuilder, int size) {
        long start = System.currentTimeMillis();
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("关键词").field("hotWords").size(size);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id.keyword");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    long value = bucket.getDocCount();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(bucket.getKey().toString());
                    nameValue.setValue((int) value);
                    list.add(nameValue);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("keyword耗时(ms)：" + (end - start));
        return list;
    }


    /**
     * 舆情数量按省分组
     *
     * @param searchSourceBuilder
     * @return
     */
    public List<NameValue> getCountGroupByProvince(SearchSourceBuilder searchSourceBuilder) {
        long start = System.currentTimeMillis();
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("关键词").field("entityProvince");
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id.keyword");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    long value = bucket.getDocCount();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(bucket.getKey().toString());
                    nameValue.setValue((int) value);
                    list.add(nameValue);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("entityProvince耗时(ms)：" + (end - start));
        return list;
    }


    /**
     * 获取关联人物词频
     *
     * @param searchSourceBuilder
     * @param size
     * @return
     * @throws IOException
     */
    public List<NameValue> getCountGroupByRelationPersonName(SearchSourceBuilder searchSourceBuilder, int size) {
        long start = System.currentTimeMillis();
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("关联人物").field("entityName").size(size);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    ValueCount count = (ValueCount) bucket.getAggregations().asMap().get("count");
                    long value = count.getValue();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(bucket.getKey().toString());
                    nameValue.setValue((int) value);
                    list.add(nameValue);
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("PersonName耗时(ms)：" + (end - start));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取关联地域词频
     *
     * @param searchSourceBuilder
     * @param size
     * @return
     * @throws IOException
     */
    public List<NameValue> getCountGroupByRelationLocationName(SearchSourceBuilder searchSourceBuilder, int size) {
        long start = System.currentTimeMillis();
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("关联地域").field("entityArea").size(size);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    ValueCount count = (ValueCount) bucket.getAggregations().asMap().get("count");
                    long value = count.getValue();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(bucket.getKey().toString());
                    nameValue.setValue((int) value);
                    list.add(nameValue);
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("LocationName耗时(ms)：" + (end - start));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取关联机构词频
     *
     * @param searchSourceBuilder
     * @param size
     * @return
     * @throws IOException
     */
    public List<NameValue> getCountGroupByRelationOrganizationName(SearchSourceBuilder searchSourceBuilder, int size) {
        long start = System.currentTimeMillis();
        List<NameValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("关联机构").field("entityOrganization").size(size);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id");
        TermsAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(valueCountAggregationBuilder);
        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    ValueCount count = (ValueCount) bucket.getAggregations().asMap().get("count");
                    long value = count.getValue();
                    NameValue nameValue = new NameValue();
                    nameValue.setName(bucket.getKey().toString());
                    nameValue.setValue((int) value);
                    list.add(nameValue);
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("OrganizationName耗时(ms)：" + (end - start));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }


    /**
     * 获取全部媒体类型
     *
     * @param searchSourceBuilder
     * @return
     */
    public List<String> getMediaTypes(SearchSourceBuilder searchSourceBuilder) {
        List<String> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("媒体类型").field("carrie").size(100);
        searchSourceBuilder.aggregation(aggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Terms terms = (Terms) a;
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    list.add(bucket.getKey().toString());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取全部月份
     *
     * @param searchSourceBuilder
     * @return
     */
    public List<String> getMonths(SearchSourceBuilder searchSourceBuilder) {
        List<String> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders.dateHistogram("publishDate").format("yyyy-MM").field("publishTime").calendarInterval(DateHistogramInterval.MONTH);
        searchSourceBuilder.aggregation(aggregationBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Histogram histogram = (Histogram) a;
                for (Histogram.Bucket bucket : histogram.getBuckets()) {
                    list.add(DateUtils.getZonedDateTimetoString((ZonedDateTime) bucket.getKey(), DateUtils.YYYY_MM));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }


    /**
     * @param sourceBuilder
     * @return
     */
    public long getMatchOpinionIdsByEvent(SearchSourceBuilder sourceBuilder) {
        try {
            return search(sourceBuilder).size();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0L;
    }


    /**
     * 判断es种是否有同id的数据，没有则插入
     *
     * @param dataList
     * @return
     * @throws IOException
     */

    public int insertOpinionIsNotExists(List<PoPublicOpinion> dataList) throws IOException {
        List<String> waitInsertData = new ArrayList<>();
        BulkRequest request = new BulkRequest();
        for (int i = 0; i < dataList.size(); i++) {
            String data = JSONObject.toJSONString(dataList.get(i));
            System.out.println("*****************************************************************");
            System.out.println("data：" + data);
            String id = dataList.get(i).getId();
            GetRequest getRequest = new GetRequest(EsIndex.OPINION, id);
            GetResponse getResult = client.get(getRequest, RequestOptions.DEFAULT);
            if (!getResult.isExists()) {
                IndexRequest indexRequest = new IndexRequest(EsIndex.OPINION, id)
                        .source(data, XContentType.JSON);
                request.add(indexRequest);
                waitInsertData.add(data);
            } else {
                System.out.println("ID:[" + id + "]数据重复");
            }
        }
        if (waitInsertData.size() > 0) {
            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
            System.out.println("request：" + request.toString());
            System.out.println("插入数据：" + response.status());
        } else {
            System.out.println("没有需要插入的数据");
        }
        return 1;
    }


    /**
     * 新增舆情
     *
     * @param jSONString
     * @param opinionId
     * @return
     */
    public int indexOpinion(String jSONString, String opinionId) {
        try {
            // 1、创建索引请求
            IndexRequest request = new IndexRequest(
                    EsIndex.OPINION);   //索引
            if (StringUtils.isEmpty(opinionId)) {
                opinionId = UUID.randomUUID().toString();
            }
            request.id(opinionId);
            request.source(jSONString, XContentType.JSON);

            //4、发送请求
            IndexResponse indexResponse = null;
            try {
                // 同步方式
                indexResponse = client.index(request, RequestOptions.DEFAULT);
            } catch (ElasticsearchException e) {
                // 捕获，并处理异常
                //判断是否版本冲突、create但文档已存在冲突
                if (e.status() == RestStatus.CONFLICT) {
                    logger.error("冲突了，请在此写冲突处理逻辑！\n" + e.getDetailedMessage());
                }

                logger.error("索引异常", e);
            }

            //5、处理响应
            if (indexResponse != null) {

                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    System.out.println("新增文档成功，处理逻辑代码写到这里。");
                    return 1;
                } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                    System.out.println("修改文档成功，处理逻辑代码写到这里。");
                    return 1;
                }
                // 分片处理信息
                ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                if (shardInfo.getTotal() != shardInfo.getSuccessful()) {

                }
                // 如果有分片副本失败，可以获得失败原因信息
                if (shardInfo.getFailed() > 0) {
                    for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                        String reason = failure.reason();
                        System.out.println("副本失败原因：" + reason);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }


    /**
     * 按照日期正负面分组
     *
     * @param searchSourceBuilder
     * @return
     */
    public List<NameListValue> getCountGroupByPublishDateSentiment(SearchSourceBuilder searchSourceBuilder) {
        List<NameListValue> list = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        DateHistogramAggregationBuilder aggregationBuilder = AggregationBuilders.dateHistogram("publishTime").format("yyyy-MM-dd").field("publishTime").dateHistogramInterval(DateHistogramInterval.DAY);
        ValueCountAggregationBuilder valueCountAggregationBuilder = AggregationBuilders.count("count").field("id.keyword");

        TermsAggregationBuilder negativeAggregationBuilder = AggregationBuilders.terms("isnegative").field("isnegative");
        negativeAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder neutralAggregationBuilder = AggregationBuilders.terms("isneutral").field("isneutral");
        neutralAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        TermsAggregationBuilder positiveAggregationBuilder = AggregationBuilders.terms("ispositive").field("ispositive");
        positiveAggregationBuilder.subAggregation(valueCountAggregationBuilder);

        DateHistogramAggregationBuilder termsAggregationBuilder = aggregationBuilder.subAggregation(negativeAggregationBuilder).subAggregation(neutralAggregationBuilder).subAggregation(positiveAggregationBuilder);

        searchSourceBuilder.aggregation(termsAggregationBuilder);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            //下面获得聚合查询
            Aggregations aggregations = search.getAggregations();
            for (Aggregation a : aggregations) {
                Histogram histogram = (Histogram) a;
                for (Histogram.Bucket bucket : histogram.getBuckets()) {
                    ZonedDateTime dateTime = (ZonedDateTime) bucket.getKey();
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    String date = dateTime.format(formatter);
                    NameListValue nameListValue = new NameListValue();
                    nameListValue.setName(date);
                    Aggregation positiveAggregation = bucket.getAggregations().asMap().get("ispositive");
                    Terms positiveTerms = (Terms) positiveAggregation;
                    List<NameValue> nameValues = new ArrayList<>();
                    for (Terms.Bucket b : positiveTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            NameValue nameValue = new NameValue();
                            nameValue.setName("ispositive");
                            nameValue.setValue((int) value);
                            nameValues.add(nameValue);

                        }
                    }

                    Aggregation neutralAggregation = bucket.getAggregations().asMap().get("isneutral");
                    Terms neutralTerms = (Terms) neutralAggregation;

                    for (Terms.Bucket b : neutralTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            NameValue nameValue = new NameValue();
                            nameValue.setName("isneutral");
                            nameValue.setValue((int) value);
                            nameValues.add(nameValue);
                        }
                    }

                    Aggregation negativeAggregation = bucket.getAggregations().asMap().get("isnegative");
                    Terms negativeTerms = (Terms) negativeAggregation;
                    for (Terms.Bucket b : negativeTerms.getBuckets()) {
                        if (b.getKey().toString().equals("1")) {
                            long value = b.getDocCount();
                            NameValue nameValue = new NameValue();
                            nameValue.setName("isnegative");
                            nameValue.setValue((int) value);
                            nameValues.add(nameValue);
                        }
                    }
                    nameListValue.setValue(nameValues);
                    list.add(nameListValue);
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }


    /**
     * 获取评论数最多的舆情列表
     *
     * @param sourceBuilder
     * @param i
     * @return
     */
    public List<PoPublicOpinion> getMainPublicOpinion(SearchSourceBuilder sourceBuilder, int i) {
        if (sourceBuilder == null) {
            sourceBuilder = new SearchSourceBuilder();
        }
        List<SortBuilder<?>> sorts = new ArrayList<>();
        SortBuilder sortBuilder = SortBuilders.fieldSort("comment").order(SortOrder.DESC).unmappedType("keyword");
        sorts.add(sortBuilder);
        sourceBuilder.sort(sorts);
        try {
            return search(sourceBuilder, PoPublicOpinion.class, i);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    /**
     * 阅读，点赞，转发
     *
     * @param searchSourceBuilder
     * @return
     */
    public Map<String, Long> getInteractiveInformation(SearchSourceBuilder searchSourceBuilder) {
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        searchSourceBuilder.size(0); // 不需要返回文档内容
        Map<String, Long> map = new HashMap<>();

        // 添加聚合
        searchSourceBuilder.aggregation(AggregationBuilders.sum("total_comments").field("comment"));
        searchSourceBuilder.aggregation(AggregationBuilders.sum("total_shares").field("forwardNum"));
        searchSourceBuilder.aggregation(AggregationBuilders.sum("total_reads").field("view"));
        searchSourceBuilder.aggregation(AggregationBuilders.sum("total_likes").field("like"));
        searchSourceBuilder.aggregation(AggregationBuilders.sum("total_lookings").field("lookingNum"));

        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            Sum totalComments = searchResponse.getAggregations().get("total_comments");
            Sum totalShares = searchResponse.getAggregations().get("total_shares");
            Sum totalReads = searchResponse.getAggregations().get("total_reads");
            Sum totalLikes = searchResponse.getAggregations().get("total_likes");
            Sum totalLookings = searchResponse.getAggregations().get("total_lookings");
            map.put("totalComments",(long)totalComments.getValue());
            map.put("totalShares",(long)totalShares.getValue());
            map.put("totalReads",(long)totalReads.getValue());
            map.put("totalLikes",(long)totalLikes.getValue());
            map.put("totalLookings",(long)totalLookings.getValue());

        } catch (IOException e) {
            e.printStackTrace();
        }

        return map;
    }

    public Map<String, Long> getInfluenceValue(SearchSourceBuilder searchSourceBuilder) {
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        // 创建Terms聚合，用于统计不同的作者
        TermsAggregationBuilder authorsAgg = AggregationBuilders.terms("authors")
                .field("author") // 替换为你的作者ID字段名
                .size(10000); // 设置返回的最大桶数，或者设置为0以获取所有唯一值

        // 创建Sum子聚合，用于计算每个作者的粉丝总数
        authorsAgg.subAggregation(AggregationBuilders.sum("total_fans").field("followersCount")); // 替换为你的粉丝数字段名
        // 创建Cardinality聚合，用于计算siteName的唯一值数量
        CardinalityAggregationBuilder uniqueAuthorsAgg = AggregationBuilders.cardinality("unique_authors").field("author");
        searchSourceBuilder.aggregation(authorsAgg);
        searchSourceBuilder.aggregation(uniqueAuthorsAgg);
        searchSourceBuilder.size(0); // 不需要返回具体的文档，只关心聚合结果
        searchRequest.source(searchSourceBuilder);
        Map<String, Long> map = new HashMap<>();
        long totalFans = 0;
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            // 获取聚合结果
            Terms authors = searchResponse.getAggregations().get("authors");
            for (Terms.Bucket entry : authors.getBuckets()) {
                String authorId = entry.getKeyAsString();
                Sum fansSum = entry.getAggregations().get("total_fans");
                long fans = (long)fansSum.getValue();
                totalFans+=fans;
            }
            Cardinality c= searchResponse.getAggregations().get("unique_authors");
            long uniqueAuthorsCount =c.getValue();
            map.put("totalFans",totalFans);
            map.put("totalAuthors",uniqueAuthorsCount);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 获取事件概要
     * @param searchSourceBuilder
     * @return
     */
    public Map<String, Object> getEventSummary(SearchSourceBuilder searchSourceBuilder) {
        SearchRequest searchRequest = new SearchRequest(EsIndex.OPINION);
        if (searchSourceBuilder == null) {
            searchSourceBuilder = new SearchSourceBuilder();
        }
        // 创建Cardinality聚合，用于计算siteName的唯一值数量
        CardinalityAggregationBuilder uniqueAuthorsAgg = AggregationBuilders.cardinality("uniqueAuthors").field("author");
        ValueCountAggregationBuilder totalArticleAgg = AggregationBuilders.count("totalArticle").field("id");
        SumAggregationBuilder totalPositiveAgg = AggregationBuilders.sum("totalPositive").field("ispositive");
        SumAggregationBuilder totalNeutralAgg = AggregationBuilders.sum("totalNeutral").field("isneutral");
        SumAggregationBuilder totalNegative = AggregationBuilders.sum("totalNegative").field("isnegative");

        searchSourceBuilder.aggregation(uniqueAuthorsAgg);
        searchSourceBuilder.aggregation(totalArticleAgg);
        searchSourceBuilder.aggregation(totalPositiveAgg);
        searchSourceBuilder.aggregation(totalNeutralAgg);
        searchSourceBuilder.aggregation(totalNegative);

        searchSourceBuilder.size(0); // 不需要返回具体的文档，只关心聚合结果
        searchRequest.source(searchSourceBuilder);
        Map<String, Object> map = new HashMap<>();

        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            // 获取聚合结果
            Cardinality c= searchResponse.getAggregations().get("uniqueAuthors");
            ValueCount valueCount= searchResponse.getAggregations().get("totalArticle");
            Sum sumPositive= searchResponse.getAggregations().get("totalPositive");
            Sum sumNeutral= searchResponse.getAggregations().get("totalNeutral");
            Sum sumNegative= searchResponse.getAggregations().get("totalNegative");

            map.put("totalAuthor",c.getValue());
            map.put("totalArticle",valueCount.getValue());
            map.put("totalPositive",sumPositive.getValue());
            map.put("totalNeutral",sumNeutral.getValue());
            map.put("totalNegative",sumNegative.getValue());

            DecimalFormat decimalFormat = new DecimalFormat("#.##"); // 保留两位小数
            if(sumPositive.getValue()>sumNeutral.getValue()&&sumPositive.getValue()>sumNegative.getValue()){
                map.put("emotion","积极");
                String formattedNumber = decimalFormat.format(sumPositive.getValue()*100/valueCount.getValue());
                map.put("proportion",formattedNumber);
            }else if(sumNeutral.getValue()>sumPositive.getValue()&&sumNeutral.getValue()>sumNegative.getValue()){
                map.put("emotion","中性");
                String formattedNumber = decimalFormat.format(sumNeutral.getValue()*100/valueCount.getValue());
                map.put("proportion",formattedNumber);
            }else if(sumNegative.getValue()>sumPositive.getValue()&&sumNegative.getValue()>sumNeutral.getValue()){
                map.put("emotion","消极");
                String formattedNumber = decimalFormat.format(sumNegative.getValue()*100/valueCount.getValue());
                map.put("proportion",formattedNumber);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;

    }
}